﻿using NAnt.Core.Attributes;
using NAnt.Core;
using NAnt.Core.Util;
using System.Xml;
using System;
using NAnt.SVN.Util;

namespace NAnt.SVN.Tasks
{
    /// <summary>
    /// Use this class to run the SVN info command
    /// You can run this tasc with the svninfo tag in NAnt.
    /// $Id$
    /// </summary>
    [TaskName("svninfo")]
    sealed public class Info : SVNTask
    {
        #region Private Fields

        private int revision = -1;
        private int remoterevision = -1;
        private Guid uuid = new Guid();
        private string repourl = "";
        private string reporooturl = "";
        private string author = "anonymous";

        #endregion

        #region Public Result Fields

        /// <summary>
        /// Revision number of the checked folder
        /// </summary>
        public int Revision
        {
            get
            {
                return revision;
            }
            set
            {
                revision = value;
            }
        }

        /// <summary>
        /// Remote revision number
        /// </summary>
        public int RemoteRevision
        {
            get
            {
                return remoterevision;
            }
            set
            {
                remoterevision = value;
            }
        }

        /// <summary>
        /// UUID of the working copy
        /// </summary>
        public Guid UUID
        {
            get
            {
                return uuid;
            }
            set
            {
                uuid = value;
            }
        }

        /// <summary>
        /// Current repository url
        /// </summary>
        public string RepoUrl
        {
            get
            {
                return repourl;
            }
            set
            {
                repourl = value;
            }
        }

        /// <summary>
        /// Root repository url
        /// </summary>
        public string RepoRootUrl
        {
            get
            {
                return reporooturl;
            }
            set
            {
                reporooturl = value;
            }
        }

        /// <summary>
        /// Author of the checked folder
        /// </summary>
        public string Author
        {
            get
            {
                return author;
            }
            set
            {
                author = value;
            }
        }

        #endregion

        /// <summary>
        /// Initialize command
        /// </summary>
        protected override void InitializeSVNTask()
        {
            Command= SVNCommands.INFO;
            Options.Add(SVNFlags.XMLOUTPUT);
        }

        /// <summary>
        /// Run the task
        /// </summary>
        protected override void ExecuteTask()
        {
            //First run the base task
            base.ExecuteTask();
            //Process the xml
            processXml();
        }

        /// <summary>
        /// Process the resulting xml
        /// </summary>
        private void processXml()
        {
            //Then extract all the data
            if (IsXmlOutput && XmlOutput != null)
            {
                //Temp vars
                XmlNodeList nodes;
                string temp;

                //Get the revision and check the validity of the xml
                nodes = XmlOutput.GetElementsByTagName("commit");
                if (nodes.Count == 1)
                {
                    //Get the value
                    temp = nodes[0].Attributes["revision"].Value;
                    //Set the revision
                    Revision = int.Parse(temp);
                    PropertiesManager.SetSVNProperty(Resources.PropertyNames.Revision, Revision);
                }
                else
                {
                    Log(Level.Warning, ResourceUtils.GetString("SVN0103"), Project.BaseDirectory);
                    return;
                }
                //Get the remote revision
                RemoteRevision = int.Parse(getAttributeFromNode("entry", "revision"));
                PropertiesManager.SetSVNProperty(Resources.PropertyNames.RemoteRevision, RemoteRevision);
                //Get the url
                RepoUrl = getInnerTextFromNode("url");
                PropertiesManager.SetSVNProperty(Resources.PropertyNames.RepoUrl, RepoUrl);
                //Get the root url
                RepoRootUrl = getInnerTextFromNode("root");
                PropertiesManager.SetSVNProperty(Resources.PropertyNames.RepoRootUrl, RepoRootUrl);
                //get the uuid
                UUID = Guid.Parse(getInnerTextFromNode("uuid"));
                PropertiesManager.SetSVNProperty(Resources.PropertyNames.UUID, UUID);
                //Get the author
                Author = getInnerTextFromNode("author");
                PropertiesManager.SetSVNProperty(Resources.PropertyNames.Author, Author);
            }
            else
            {
                Log(Level.Info, ResourceUtils.GetString("SVN0103"), Project.BaseDirectory);
            }
        }

        #region Util functions

        /// <summary>
        /// Get the inner text of a node
        /// </summary>
        /// <param name="xml"></param>
        /// <param name="tagname"></param>
        /// <returns></returns>
        private string getInnerTextFromNode(string tagname)
        {
            XmlNodeList nodes = XmlOutput.GetElementsByTagName(tagname);
            return nodes[0].InnerText;
        }

        /// <summary>
        /// Get an attribute value
        /// </summary>
        /// <param name="xml"></param>
        /// <param name="tagname"></param>
        /// <param name="attrname"></param>
        /// <returns></returns>
        private string getAttributeFromNode(string tagname, string attrname)
        {
            XmlNodeList nodes = XmlOutput.GetElementsByTagName(tagname);
            return nodes[0].Attributes[attrname].Value;
        }

        #endregion
    }
}
